import sys
import threading
import traceback
import re
from PyQt4 import QtCore, QtGui
from mwd import Ui_mwd

# make simple replace
class HtmlReplacer(object):
    mods = {'>': '&gt;', '<': '&lt;'}
    def __call__(self, raw):
        for k,v in self.mods.iteritems():
            raw = raw.replace(k,v)
        return raw

# make replace in regexp
class ProtectedHtmlReplacer(HtmlReplacer):
    mods = {'\>': '&gt;', '\<': '&lt;'}

# inverse replace
class InverseHtmlReplacer(HtmlReplacer):
    mods = {'&gt;': '>', '&lt;': '<'}

# create instances of objects, for make easier call
htmlReplace, protectedReplace, inverseReplace = HtmlReplacer(), ProtectedHtmlReplacer(), InverseHtmlReplacer()

# this project valid exception
class SmartError(Exception): pass

# advanced regexp evaluting
class ObserveHtmlWidget(object): 
    phtml = '<span style="background-color:#BFE4FF; color:#0066B3; padding:2px;">%s</span>'
    def _exec(self, func, value, ignoreExc):
        try:
            value = func(value)
        except ignoreExc, e:
            raise SmartError('%s: %s' % (type(e).__name__, e[0]))
        return value

    def __call__(self, text='', regexp=''):
        if regexp=='':
            return
        html, groups = '', []

        text,regexp = htmlReplace(text), protectedReplace(regexp)
        ptn = self._exec(re.compile, regexp, re.error)
        matches = self._exec(ptn.search, text, Exception)
        while (matches and text<>''):
            s, e, v = matches.start(), matches.end(), matches.group()
            groups.append(matches.groups())
            html += text[:s]+self.phtml % v
            if e==0: 
                text = text[1:]
            else:               # null valued iterations
                text = text[e:]
            matches = ptn.search(text)
        return (html+text, groups)

class Wnd(QtGui.QMainWindow): 
    _timer = None
    SIGNAL_prepared = QtCore.SIGNAL('prepared(QString)')
    SIGNAL_excRaise = QtCore.SIGNAL('exceptionRaise(QString)')
    _observer = ObserveHtmlWidget()

    def __init__(self, ui): 
        QtGui.QMainWindow.__init__(self)
        self.ui = ui
        QtCore.QObject.connect(self, self.SIGNAL_prepared, self.onPrepared)
        QtCore.QObject.connect(self, self.SIGNAL_excRaise, self.onRaiseException)

    def callSearchRegExp(self):
        txt, rg = unicode((self.ui.eText.toPlainText())), unicode(self.ui.eReg.toPlainText())
        self.ui.statusBar.clearMessage()
        try:
            data = self._observer(txt, rg)
        except SmartError, e:
            self.emit(self.SIGNAL_excRaise, e[0]);
            return
        if (data):
            self.emit(self.SIGNAL_prepared, data[0])
            self.showGroups(data[1])

    def callTimerForRegExp(self):
        if (self._timer):
            self._timer.cancel()
        self._timer = threading.Timer(1, self.callSearchRegExp)
        self._timer.start()    

    def onPrepared(self, value):
        self.ui.eHtml.setHtml(value)

    def onRaiseException(self, value):
        self.ui.statusBar.showMessage(value)

    def showGroups(self, rows):
        self.ui.lvas.clear()
        for e in rows:
            if isinstance(e, tuple):
                prepared = [inverseReplace(i) for i in e]
                self.ui.lvas.addItem(', '.join(prepared))
            else:
                self.ui.lvas.addItem(inverseReplace(e))

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    ui = Ui_mwd()
    form = Wnd(ui)
    ui.setupUi(form)
    form.show()
    form.callSearchRegExp()             # for first time evalution
    sys.exit(app.exec_())
